import torch
import time
import torch.nn as nn
import psutil

def monitor_cpu_gpu():
    cpu_percent = psutil.cpu_percent(interval=0.1)
    if torch.cuda.is_available():
        gpu_percent = torch.cuda.memory_allocated() / torch.cuda.memory_reserved() * 100
    else:
        gpu_percent = 0


# 专家模型
class RLExpert(nn.Module):
    def __init__(self):
        super(RLExpert, self).__init__()
        self.fc1 = nn.Linear(14, 32)
        self.fc2 = nn.Linear(32, 64)
        self.fc3 = nn.Linear(64, 64)
        self.fc4 = nn.Linear(64, 32)
        self.fc5 = nn.Linear(32, 4)

        self.gelu = nn.GELU()

    def forward(self, x):
        x = self.gelu(self.fc1(x))
        x = self.gelu(self.fc2(x))
        x = self.gelu(self.fc3(x))
        x = self.gelu(self.fc4(x))
        return torch.softmax(self.fc5(x), dim=-1)


class MoE(nn.Module):
    def __init__(self, experts, gate):
        super(MoE, self).__init__()
        self.experts = nn.ModuleList(experts)
        self.gate = gate

    def forward(self, x):
        gate_weights = self.gate(x)  # 33x3

        start_time = time.time()
        expert_outputs = [expert(x) for expert in self.experts]  # 3x33x4

        return torch.stack([expert_outputs[i] * gate_weights[:, i].unsqueeze(1) for i in range(len(self.experts))]).sum(0)


# 门控网络
class GateNetwork(nn.Module):
    def __init__(self, input_dim=14, hidden_dim=32, num_experts=3):
        super(GateNetwork, self).__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.fc2 = nn.Linear(hidden_dim, hidden_dim)
        self.fc3 = nn.Linear(hidden_dim, num_experts)

        self.gelu = nn.GELU()
        self.dropout = nn.Dropout(0.2)

    def forward(self, x):
        x = self.gelu(self.fc1(x))
        x = self.dropout(x)
        x = self.gelu(self.fc2(x))
        x = self.fc3(x)
        return torch.softmax(x, dim=-1)